﻿using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;

namespace Rabbitmq.Client2Api.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class SmsController : ControllerBase
    {

        private readonly ILogger<SmsController> _logger;
        private readonly RabbitMQMessageService _rabbitMqService;
        public SmsController(ILogger<SmsController> logger)
        {
            _logger = logger;
            _rabbitMqService = new RabbitMQMessageService();
        }

        /// <summary>
        /// 发送短信
        /// </summary>
        /// <returns></returns>
        [HttpPost("sendSms")]
        public void SendSmsAsync()
        {
            /**
             * 扇形交换机-消费者
             * **/

            //建立连接
            var factory = new ConnectionFactory()
            {
                HostName = "localhost",
                Port = 5672,
                Password = "guest",
                UserName = "guest",
                VirtualHost = "/"
            };
            var connection = factory.CreateConnection();
            var channel = connection.CreateModel();

            // 1、定义交换机
            channel.ExchangeDeclare(exchange: "test_fanout_message", type: ExchangeType.Fanout);

            // 2、定义随机队列
            var queueName = channel.QueueDeclare().QueueName;

            // 3、队列要和交换机绑定起来
            channel.QueueBind(queueName, "test_fanout_message", routingKey: "test_fanout_message");

            var consumer = new EventingBasicConsumer(channel);
            consumer.Received += (model, ea) =>
            {
                Console.WriteLine($"model:{model}");
                var body = ea.Body;
                // 1、业务逻辑
                var message = Encoding.UTF8.GetString(body.ToArray());
                Console.WriteLine(" [x] 发送短信 {0}", message);

                // 自动确认机制缺陷：
                // 1、消息是否正常添加到数据库当中,所以需要使用手工确认
                channel.BasicAck(ea.DeliveryTag, true);
            };
            // 3、消费消息
            channel.BasicQos(0, 1, false); // Qos(防止多个消费者，能力不一致，导致的系统质量问题。
                                           // 每一次一个消费者只成功消费一个)
            channel.BasicConsume(queue: queueName,
                                 autoAck: false, // 手动消息确认(防止消息消费失败)
                                 consumer: consumer);

            Console.WriteLine("发送短信监听...");

        }

        /// <summary>
        /// 直连交换机消费者
        /// </summary>
        [HttpPost("addUser_Direct")]
        public void TestDirect()
        {
            //直连交换机
            var factory = new ConnectionFactory()
            {
                HostName = "localhost",
                Port = 5672,
                Password = "guest",
                UserName = "guest",
                VirtualHost = "/"
            };
            var connection = factory.CreateConnection();
            var channel = connection.CreateModel();

            //1、定义交换机
            channel.ExchangeDeclare(exchange: "adduser_direct", type: ExchangeType.Direct);

            //2、定义随机队列
            var queueName = channel.QueueDeclare().QueueName;

            //3、队列绑定交换机
            channel.QueueBind(queueName, "adduser_direct",
                routingKey: "adduser-sms");

            //4、监听队列
            var consumer = new EventingBasicConsumer(channel);
            consumer.Received += (model, ea) =>
            {
                Console.WriteLine($"model:{model}");
                var body = ea.Body;
                Console.WriteLine("处理添加用户业务逻辑");
                //......

                var message = Encoding.UTF8.GetString(body.ToArray());
                Console.WriteLine("发送消息内容：{message}");

                channel.BasicAck(ea.DeliveryTag, true);
            };

            //5、消费消息(Qos(防止多个消费者，能力不一致导致的系统质量问题)
            //每次一个消费者只能成功消费一次
            channel.BasicQos(0, 1, false);

            channel.BasicConsume(queue: queueName,
                autoAck: false, //消息确认，防止消费失败
                consumer: consumer);

            Console.WriteLine("开始监听。。。。");
        }

        /// <summary>
        /// RPC交换机模式-消费者
        /// </summary>
        [HttpPost("rpcDataCreate")]
        public void CreateDataTest()
        {
            // 1、创建连接
            var factory = new ConnectionFactory()
            {
                HostName = "localhost",
                Port = 5672,
                Password = "guest",
                UserName = "guest",
                VirtualHost = "/"
            };
            var connection = factory.CreateConnection();

            #region 创建数据-Rpc回调

            var channel = connection.CreateModel();

            //2、定义随机队列(用完之后立马删除)
            var queueName = channel.QueueDeclare(queue: "teacher_add",
                                                 durable: false,
                                                 exclusive: false,
                                                 autoDelete: false,
                                                 arguments: null);
            var consumer = new EventingBasicConsumer(channel);

            consumer.Received += (model, ea) =>
            {
                Console.WriteLine($"model:{model}");
                var body = ea.Body;

                var props = ea.BasicProperties;
                var replyProps = channel.CreateBasicProperties();
                replyProps.CorrelationId = props.CorrelationId;

                try
                {
                    // 执行业务
                    var message = Encoding.UTF8.GetString(body.ToArray());
                    Console.WriteLine(" [x] 创建作业_RPC" +
                        " {0}", message);
                }
                catch (Exception e)
                {
                    Console.WriteLine(" [.] " + e.Message);
                }
                finally
                {
                    Console.WriteLine("发送回调消息_RPC");
                    var responseBytes = Encoding.UTF8.GetBytes("RPC_商品回调成功");
                    channel.BasicPublish(exchange: "",
                                        routingKey: props.ReplyTo,
                                        basicProperties: replyProps,
                                        body: responseBytes);
                    /*channel.BasicAck(deliveryTag: ea.DeliveryTag,
                      multiple: false);*/
                }
            };

            // 3、消费消息
            channel.BasicQos(0, 1, false); // Qos(防止多个消费者，能力不一致，导致的系统质量问题。每一次一个消费者只成功消费一个)
            channel.BasicConsume(queue: "teacher_add",
                                 autoAck: true, // 消息确认(防止消息消费失败)
                                 consumer: consumer);
            #endregion
            Console.WriteLine("开启作业创建监听.....");

        }

        /// <summary>
        /// 主题交换机-消费者（Topic Exchange）
        /// </summary>
        [HttpPost("topicSubscribe")]
        public void CreateTopicUser()
        {
            // 场景：添加商品是否成功
            #region 1、创建用户-发送短信 
            {
                // 1、创建连接
                var factory = new ConnectionFactory()
                {
                    HostName = "localhost",
                    Port = 5672,
                    Password = "guest",
                    UserName = "guest",
                    VirtualHost = "/"
                };
                var connection = factory.CreateConnection();
                var channel = connection.CreateModel();

                // 1、定义交换机
                channel.ExchangeDeclare(exchange: "sms_topic", type: ExchangeType.Topic);

                // 2、定义随机队列
                var queueName = channel.QueueDeclare().QueueName;

                // 3、队列要和交换机绑定起来。多对1
                // * 号的缺陷：只能匹配一级
                // # 能够匹配一级及多级以上
                // 真实项目当中，使用主题交换机。因为：可以满足所有场景
                channel.QueueBind(queueName,
                                      "sms_topic",
                                      routingKey: "sms.#");

                var consumer = new EventingBasicConsumer(channel);
                consumer.Received += (model, ea) =>
                {
                    Console.WriteLine($"model:{model}");
                    var body = ea.Body;
                    // 1、业务逻辑
                    var message = Encoding.UTF8.GetString(body.ToArray());
                    Console.WriteLine(" [x] 发送短信 {0}", message);

                    // 自动确认机制缺陷：
                    // 1、消息是否正常添加到数据库当中,所以需要使用手工确认
                    channel.BasicAck(ea.DeliveryTag, true);
                };
                // 3、消费消息
                channel.BasicQos(0, 1, false); // Qos(防止多个消费者，能力不一致，导致的系统质量问题。
                                               // 每一次一个消费者只成功消费一个)
                channel.BasicConsume(queue: queueName,
                                     autoAck: false, // 消息确认(防止消息消费失败)
                                     consumer: consumer);
            }
            #endregion

            Console.WriteLine("短信创建监听......");

        }

    }
}
